package com.ipzoe.common.component.filter;

import com.ipzoe.common.bean.entity.Admin;
import com.ipzoe.common.bean.entity.Profile;
import com.ipzoe.common.component.TokenComponent;
import com.ipzoe.common.service.AdminService;
import com.ipzoe.common.service.ProfileService;
import com.ipzoe.common.util.StringUtil;
import io.jsonwebtoken.JwtException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.GenericFilterBean;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 身份过滤器. 通过Header中的X-Auth-Token项, jwt校验.
 * <p>
 * 此过滤器需要在跨域过滤器过滤后执行.
 * <p>
 * Created on 16/8/8.
 *
 * @author xingfinal
 */
@Component
@Order(3)
public class AuthenticationTokenFilter extends GenericFilterBean {
    private Log log = LogFactory.getLog(getClass());

    @Value("${eva.token.header}")
    private String tokenHeader;

    @Autowired
    private TokenComponent tokenComponent;

    @Autowired
    private ProfileService profileService;

    @Autowired
    private AdminService adminService;

    @Override
    public void doFilter(ServletRequest req, ServletResponse res,
                         FilterChain chain) throws IOException, ServletException {
        final HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;

        // 不过滤OPTIONS请求
        if (request.getMethod().equalsIgnoreCase(HttpMethod.OPTIONS.toString())) {
            chain.doFilter(req, res);
            return;
        }

        // 只对以'/api/'和'/admin/'开头的接口进行身份校验控制
        if (!request.getServletPath().startsWith("/api/")
                && !request.getServletPath().startsWith("/admin/")) {
            chain.doFilter(req, res);
            return;
        }

        // X-Auth-Token携带确认
        final String authHeader = request.getHeader(tokenHeader);
        if (authHeader == null || !authHeader.startsWith("Bearer ")) {
            response.setStatus(HttpStatus.FORBIDDEN.value());
            return;
        }

        final String token = authHeader.substring(7); // The part after
        // "Bearer "
        if (request.getServletPath().startsWith("/api")) {
            String accountId;
            try {
                accountId = tokenComponent.getUsernameFromToken(token);
            } catch (JwtException e) {
                response.setStatus(HttpStatus.FORBIDDEN.value());
                return;
            }
            if (!StringUtil.isNotEmpty(accountId)) {
                response.setStatus(HttpStatus.FORBIDDEN.value());
                return;
            }
            if (!tokenComponent.validateToken(token, accountId, TokenComponent.ROLE_USER)) {
                response.setStatus(HttpStatus.FORBIDDEN.value());
                return;
            }

            Profile profile = profileService.selectById(Long.valueOf(accountId));
            if (null == profile) {
                response.sendError(HttpStatus.FORBIDDEN.value(), "用户不存在");
                return;
            } else if (Profile.STATUS_BLOCKED.equals(profile.getStatus())) {
                response.sendError(HttpStatus.FORBIDDEN.value(), "用户被冻结, 请联系管理员");
                return;
            }
            req.setAttribute("profile", profile);
        } else if (request.getServletPath().startsWith("/admin")) {
            String adminId;
            try {
                adminId = tokenComponent.getRoleFromToken(token);
            } catch (JwtException e) {
                response.setStatus(HttpStatus.FORBIDDEN.value());
                return;
            }
            if (!StringUtil.isNotEmpty(adminId)) {
                response.setStatus(HttpStatus.FORBIDDEN.value());
                return;
            }
            Admin admin = adminService.selectById(Long.valueOf(adminId));
            if (null == admin) {
                response.sendError(HttpStatus.FORBIDDEN.value(), "用户不存在");
                return;
            }else if(Admin.STATUS_BLOCKED.equals(admin.getStatus())){
                response.sendError(HttpStatus.FORBIDDEN.value(), "用户被冻结, 请联系管理员");
                return;
            }
            req.setAttribute("admin", admin);
        }

        chain.doFilter(req, res);
    }

}
